package ru.chaykin.util;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;

import android.opengl.GLSurfaceView;
import android.util.Log;

/**
 * Находит и устанавливает наиболее подходящую конфигурацию OpenGL
 * @author k.chaykin
 *
 */
public abstract class EGLCfg {
	
	/**
	 * Оптимальная конфигурация для правильной работы приложения
	 */
	private static final short[] OPT_EGL = new short[] {8, 8, 8, 8, 16, 8};
	
	/**
	 * Минимальная конфигурация для правильной работы приложения
	 */
	private static final short[] MIN_EGL = new short[] {1, 1, 1, 1, 1, 1};
	
	private static int[] config = new int[6];
	
	private static void addOption(EGLCfgEnum id, int option) {
		config[id.getValue()] = option;
	}
	
	/**
	 * Устанавливает подходящую конфигурацию
	 */
	public static void setOptimalEGLConfig(GLSurfaceView surface) {
		int[] minConfig = null;
		EGL10 egl = (EGL10)EGLContext.getEGL();
		EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

		int[] version = new int[2];
		egl.eglInitialize(dpy, version);

		EGLConfig[] conf = new EGLConfig[100];
		int[] num_conf = new int[1];
		egl.eglGetConfigs(dpy, conf, 100, num_conf);

		for(int i = 0; i < num_conf[0]; i++)
		{
			int[] value = new int[1];
			if (conf[i] != null)
			{
				egl.eglGetConfigAttrib(dpy, conf[i], EGL10.EGL_RED_SIZE, value);
				addOption(EGLCfgEnum.RED, value[0]);
				egl.eglGetConfigAttrib(dpy, conf[i], EGL10.EGL_GREEN_SIZE, value);
				addOption(EGLCfgEnum.GREEN, value[0]);
				egl.eglGetConfigAttrib(dpy, conf[i], EGL10.EGL_BLUE_SIZE, value);
				addOption(EGLCfgEnum.BLUE, value[0]);
				egl.eglGetConfigAttrib(dpy, conf[i], EGL10.EGL_ALPHA_SIZE, value);
				addOption(EGLCfgEnum.ALPHA, value[0]);
				egl.eglGetConfigAttrib(dpy, conf[i], EGL10.EGL_DEPTH_SIZE, value);
				addOption(EGLCfgEnum.DEPTH, value[0]);
				egl.eglGetConfigAttrib(dpy, conf[i], EGL10.EGL_STENCIL_SIZE, value);
				addOption(EGLCfgEnum.STENCIL, value[0]);
				Log.d(EGLCfg.class.getName(), "Available EGL config (" + i + "): " + 
						config[EGLCfgEnum.RED.getValue()] + ", " + config[EGLCfgEnum.GREEN.getValue()] + ", " + 
						config[EGLCfgEnum.BLUE.getValue()] + ", " + config[EGLCfgEnum.ALPHA.getValue()] + ", " + 
						config[EGLCfgEnum.DEPTH.getValue()] + ", " + config[EGLCfgEnum.STENCIL.getValue()]);
				if (isSituable(OPT_EGL)) {
					setEGLConfig(surface);
					return;
				}
				if (isSituable(MIN_EGL)) {
					minConfig = config;
				}
			}
		}
		if (minConfig != null) {
			config = minConfig;
			setEGLConfig(surface);
		}
		else {
			surface.setEGLConfigChooser(false); //Если не нашли подходящей конфигурации, установим эту.
			Log.d(EGLCfg.class.getName(), "Aplayed EGL config: default");
		}
	}
	
	/**
	 * Возвращает <code>true</code>, если конфигурация подходящая
	 * @return
	 */
	private static boolean isSituable(short[] egl) {
		return config[EGLCfgEnum.RED.getValue()] >= egl[EGLCfgEnum.RED.getValue()] && 
			   config[EGLCfgEnum.GREEN.getValue()] >= egl[EGLCfgEnum.GREEN.getValue()] && 
			   config[EGLCfgEnum.BLUE.getValue()] >= egl[EGLCfgEnum.BLUE.getValue()] && 
			   config[EGLCfgEnum.ALPHA.getValue()] >= egl[EGLCfgEnum.ALPHA.getValue()] && 
			   config[EGLCfgEnum.DEPTH.getValue()] >= egl[EGLCfgEnum.DEPTH.getValue()] && 
			   config[EGLCfgEnum.STENCIL.getValue()] >= egl[EGLCfgEnum.STENCIL.getValue()];
	}
	
	private static void setEGLConfig(GLSurfaceView surface) {
		surface.setEGLConfigChooser(config[EGLCfgEnum.RED.getValue()], config[EGLCfgEnum.GREEN.getValue()], 
				                    config[EGLCfgEnum.BLUE.getValue()], config[EGLCfgEnum.ALPHA.getValue()], 
				                    config[EGLCfgEnum.DEPTH.getValue()], config[EGLCfgEnum.STENCIL.getValue()]);
		Log.d(EGLCfg.class.getName(), "Aplayed EGL config: " + config[EGLCfgEnum.RED.getValue()] + ", " + config[EGLCfgEnum.GREEN.getValue()] + ", " + 
									config[EGLCfgEnum.BLUE.getValue()] + ", " + config[EGLCfgEnum.ALPHA.getValue()] + ", " + 
									config[EGLCfgEnum.DEPTH.getValue()] + ", " + config[EGLCfgEnum.STENCIL.getValue()]);
	}
	
	public enum EGLCfgEnum {
		
		RED(0), BLUE(1), GREEN(2), ALPHA(3), DEPTH(4), STENCIL(5);
		
		private int value;
		
		EGLCfgEnum(int value) {
			this.value = value;
		}
		
		public int getValue() {
			return value;	        
		}
	}
}